package com.ibm.db2oncampus.portal.usuario.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.ibm.db2oncampus.portal.framework.service.AbstractService;
import com.ibm.db2oncampus.portal.framework.service.InvalidDataException;
import com.ibm.db2oncampus.portal.usuario.domain.Certification;
import com.ibm.db2oncampus.portal.usuario.domain.Experience;
import com.ibm.db2oncampus.portal.usuario.domain.Person;
import com.ibm.db2oncampus.portal.usuario.domain.Role;
import com.ibm.db2oncampus.portal.usuario.persistence.PersonDao;
import com.ibm.db2oncampus.portal.usuario.persistence.RoleDao;
import com.ibm.db2oncampus.portal.usuario.service.PersonService;
import com.ibm.db2oncampus.portal.util.Validadores;

public class PersonServiceImpl extends AbstractService implements PersonService {

	PersonDao personDao;
	RoleDao roleDao;
	
	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}
	
	public void setRoleDao(RoleDao roleDao) {
		this.roleDao = roleDao;
	}
	
	@Override
	public void remove(Person p) {
		// Check if there isn't any group this user owns
		personDao.remove(p);
	}

	@Override
	public void save(Person p) throws InvalidDataException {

		this.validateUserData(p, false);

		if(this.getErrors().isEmpty()) {
			Role mainRole = roleDao.findRoleByName(p.getUserType());
			
			if(mainRole == null) {
				this.addError("The role " + p.getUserType() + " could not be found");
			} else {
				p.getRolesPlayed().add(mainRole);
			}
			
			Person samePerson = personDao.findPersonByUserId(p.getUserId());
			if(samePerson != null) {
				this.addError("There is a user already registered with this Id. Please choose a new one.");
			}
		}

		if(this.getErrors().isEmpty()) {
			p.setRegistrationDate(new Date());
			p.setActiveProfile(true);
			personDao.save(p);
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to register a new user: " + this.getErrors());
		}
	}
	
	public void saveCompleteProfile(Person p) throws InvalidDataException {
		this.validateUserData(p, true);
		
		if(this.getErrors().isEmpty()) {
			
			List<Experience> experienceList = new ArrayList<Experience>(p.getExperience());
			
			personDao.save(p);
			
			List<Experience> listExperienceRemove = personDao.listExperienceNotInCollectionByPerson(p, experienceList);
			if (listExperienceRemove != null && (! listExperienceRemove.isEmpty())) {
				for (Experience e : listExperienceRemove) {
					personDao.removeExperience(e);
				}
			}
			
			
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to save the user complete profile: " + this.getErrors());
		}
	}
	
	public void assignRolesToPerson(Person p, List<Role> rolesToAdd) {
		p.getRolesPlayed().addAll(rolesToAdd);
		personDao.save(p);
	}
	
	public void unassignRolesToPerson(Person p, List<Role> rolesToRemove) {
		p.getRolesPlayed().removeAll(rolesToRemove);
		personDao.save(p);
	}
	
	private void validateUserData(Person p, boolean completeProfile) throws InvalidDataException {
		if(p.getUserId() == null || "".equals(p.getUserId())) {
			this.addError("User Id cannot be blank");
		}
		
		if(p.getPassword() == null || "".equals(p.getUserId())) {
			this.addError("Password cannot be blank");
		}
		
		if(p.getPassword() != null && !"".equals(p.getUserId()) && p.getPassword().length() < 8) {
			this.addError("Password should have at least 8 characters");
		}
		
		if(p.getFirstName() == null || "".equals(p.getFirstName())) {
			this.addError("First name cannot be blank");
		}
		
		if(p.getLastName() == null || "".equals(p.getLastName())) {
			this.addError("Last name cannot be blank");
		}
		
		if(p.getUserType() == null || "".equals(p.getUserType())) {
			this.addError("User type cannot be blank");
		}
		
		if(p.getCountry() == null || "".equals(p.getUserType())) {
			this.addError("Country cannot be blank");
		}
		
		// Data to be validated when the user is filling the complete profile form
		if(completeProfile) {
			for(Experience e : p.getExperience()) {
				
				if(e.getStartDate() != null && e.getEndDate() != null) {
					if(e.getStartDate().after(e.getEndDate())) {
						this.addError("Start date cannot be after End date");
					}
				}
				
				if(e instanceof Certification) {
					Certification certification = (Certification) e;
					if(certification.getExpirable() && (certification.getEndDate() == null)) {
						this.addError("For certifications that are expirable, End Date cannot be blank");
					}
				}
			}
		}
	}

	@Override
	public void addExperienceToUser(Person p, Experience e) {
		p.getExperience().add(e);
		personDao.save(p);
		
	}

	@Override
	public List<Person> listPersonByCertification(String certificationName) throws InvalidDataException {
		List<Person> list = null;
		
		if (Validadores.isStringEmpty(certificationName)) {
			this.addError("The Certification Name is required");
		} else {
			list = personDao.listPersonByCertification(certificationName);
			if (Validadores.isCollectionEmpty(list)) {
				this.addError("No results were found");
			}
		}
		
		if (this.getErrors().isEmpty()) {
			return list;
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to search for an user: " + this.getErrors());
		}
	}

	@Override
	public List<Person> listPersonByJob(String byJobName, String byJobDescription, String byJobSkill) throws InvalidDataException {
		List<Person> list = null;
		
		if (Validadores.isStringEmpty(byJobName) && Validadores.isStringEmpty(byJobDescription) && Validadores.isStringEmpty(byJobSkill)) {
			this.addError("One of the fields must be filled out");
		} else {
			list = personDao.listPersonByJob(byJobName, byJobDescription, byJobSkill);
			if (Validadores.isCollectionEmpty(list)) {
				this.addError("No results were found");
			}
		}
		
		if (this.getErrors().isEmpty()) {
			return list;
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to search for an user: " + this.getErrors());
		}
	}

	@Override
	public List<Person> listPersonByName(String name) throws InvalidDataException {
		List<Person> list = null;
		
		if (Validadores.isStringEmpty(name)) {
			this.addError("The User Name is required");
		} else {
			list = personDao.listPersonByName(name);
			if (Validadores.isCollectionEmpty(list)) {
				this.addError("No results were found");
			}
		}
		
		if (this.getErrors().isEmpty()) {
			return list;
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to search for an user: " + this.getErrors());
		}
	}

	@Override
	public List<Person> listPersonByOtherSkill(String otherSkillName) throws InvalidDataException {
		List<Person> list = null;
		
		if (Validadores.isStringEmpty(otherSkillName)) {
			this.addError("The Skill Name is required");
		} else {
			list = personDao.listPersonByOtherSkill(otherSkillName);
			if (Validadores.isCollectionEmpty(list)) {
				this.addError("No results were found");
			}
		}

		if (this.getErrors().isEmpty()) {
			return list;
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to search for an user: " + this.getErrors());
		}
	}

	@Override
	public List<Person> listPersonByScholarship(String courseName, String level) throws InvalidDataException {
		List<Person> list = null;
		
		if (Validadores.isStringEmpty(courseName) && Validadores.isStringEmpty(level)) {
			this.addError("One of the fields must be filled out");
		} else {
			list = personDao.listPersonByScholarship(courseName, level);
			if (Validadores.isCollectionEmpty(list)) {
				this.addError("No results were found");
			}
		}
		
		if (this.getErrors().isEmpty()) {
			return list;
		} else {
			throw new InvalidDataException("The following problems occurred on an attempt to search for an user: " + this.getErrors());
		}
	}

	@Override
	public Person findPersonById(Long id) {
		return personDao.findById(id);
	}

	@Override
	public Person findPersonByUserId(String userId) {
		return personDao.findPersonByUserId(userId);
	}

	@Override
	public Experience findExperienceById(Long experienceId) {
		return personDao.findExperienceById(experienceId);
	}
	
	public List<Role> listRolesByPerson(Person person) {
		List<Role> roles = null;
		
		if (person == null) {
			roles = this.listAnonymousRoles();
		} else {
			roles = new ArrayList<Role>(person.getRolesPlayed());
		}
		return roles;
	}
	
	public List<Role> listAnonymousRoles() {
		return roleDao.listAnonymousRoles();
	}
}